from common_data import *
from permission import *
from twisted.web import xmlrpc
from twisted.python import log
from datetime import datetime,timedelta

class XMLRPC_CheckoutResource( xmlrpc.XMLRPC ):
    _permissions = {
        'addCheckout':                  PERMISSION_REQUIREMENT_PARTY_ADMIN,
        'getCheckoutByEnvironmentID':   PERMISSION_REQUIREMENT_PARTY_ADMIN,
        'getCheckoutByID':              PERMISSION_REQUIREMENT_PARTY_ADMIN,
        'getCheckoutsByPartyID':        PERMISSION_REQUIREMENT_PARTY_ADMIN,
        'listCheckouts':                PERMISSION_REQUIREMENT_PARTY_ADMIN,
        'delCheckout':                  PERMISSION_REQUIREMENT_PARTY_ADMIN,    
        }
    
    def __init__(self):
        """ load config
        """
        log.msg( 'Checkout resource init' )
        xmlrpc.XMLRPC.__init__(self)
    
    def xmlrpc_listCheckouts(self, low_date_range = None, high_date_range = None ):
        """return list of current checkouts"""

        if high_date_range and not low_date_range:
            raise xmlrpc.Fault( 123, 'high date range cannot be submitted with low date range' )
        
        search_condition = None
        
        if low_date_range:
            try:
                low_datetime = datetime.strptime( str( low_date_range ), '%Y%m%dT%H:%M:%S' )
            except:
                log.err( 'could not convert low_date_range to datetime. low_date_range: %s' % str( low_date_range ) )
                log.err()
                raise xmlrpc.Fault( 123, 'could not interpret low date range' )
            
            if high_date_range:
                try:
                    high_datetime = datetime.strptime( str( high_date_range ), '%Y%m%dT%H:%M:%S' )
                except:
                    log.err( 'could not convert high_date_range to datetime. high_date_range: %s' % str( high_date_range ) )
                    log.err()
                    raise xmlrpc.Fault( 123, 'could not interpret high date range' )
                
                search_condition = AND( Checkout.q.expiration_time >= low_datetime, Checkout.q.expiration_time <= high_datetime )
            else:
                search_condition = AND( Checkout.q.expiration_time >= low_datetime )
                
        try:
            checkouts = Checkout.select( search_condition, orderBy=Checkout.q.id )
        except IndexError:
            raise xmlrpc.Fault( 123, 'not found' )
        except:
            log.err( 'could not retrieve checkouts. low_date_range: %s, high_date_range: %s' % ( str( low_date_range ), str( high_date_range ) ) )
            log.err()
            raise xmlrpc.Fault( 123, 'could not retrieve checkouts' )
             
        return list( ( checkout.id, xmlrpc.DateTime( checkout.expiration_time ).value ) for checkout in checkouts )
    
    xmlrpc_listCheckouts.signature = [ ['array','string'],
                                      ['array','string'],
                                      ['array','string','string' ],
                                      ]
    
    def xmlrpc_getCheckoutByEnvironmentID(self, environment_id ):
        """get checkout by environment id"""
        
        if not int( environment_id ):
            raise xmlrpc.Fault( 123, 'invalid argument' )
        
        try:
            checkout = Checkout.selectBy( environment = int( environment_id ) ).getOne()
        except SQLObjectNotFound:
            raise xmlrpc.Fault( 123, 'checkout not found' )
        except:
            log.err( 'could not retrieve checkout. environment_id: %d' % int( environment_id ) )
            log.err()
            raise xmlrpc.Fault( 123, 'could not retrieve checkout' )
                    
        return self.checkoutResultToDict( checkout )
    
    xmlrpc_getCheckoutByEnvironmentID.signature = [ ['array','int'] ]
    
    def xmlrpc_getCheckoutByID(self, checkout_id ):
        """get checkout by id"""
        
        if not int( checkout_id ):
            raise xmlrpc.Fault( 123, 'invalid argument' )
        
        checkout = getCheckoutById( checkout_id )
                    
        return self.checkoutResultToDict( checkout )
    
    xmlrpc_getCheckoutByID = [ ['array','int'] ]
    
    def xmlrpc_getCheckoutsByPartyID(self, party_id ):
        """get checkout by party id"""
        
        if not int( party_id ):
            raise xmlrpc.Fault( 123, 'invalid argument' )
        
        try:
            checkouts = list( Checkout.selectBy( party = int( party_id ) ) )
        except:
            log.err( 'could not retrieve checkouts. party_id: %d' % int( party_id ) )
            log.err()
            raise xmlrpc.Fault( 123, 'could not retrieve checkouts' )
        
        if not len( checkouts ):
            raise xmlrpc.Fault( 123, 'checkout not found' )
        
        result = list()
        
        for checkout in checkouts:
            result.append( self.checkoutResultToDict(checkout) )
               
        return result
    
    xmlrpc_getCheckoutsByPartyID.signature = [['array','int']]
    
    def xmlrpc_delCheckout(self, party_id, checkout_id ):
        """delete an existing checkout"""
        
        if not int( checkout_id ):
            raise xmlrpc.Fault( 123, 'invalid arguments' )
        
        party = getPartyById( party_id )
        target_checkout = getCheckoutById( checkout_id )

        # validate that checkout is assigned to submitted party
        if target_checkout.party.id != party.id:
            log.err( 'attempt to remove checkout from a non-assigned party. party_id: %d, checkout_id: %d' % ( party_id, checkout_id ) )
            raise xmlrpc.Fault( 123, 'submitted checkout is not assigned to submitted party' )
                
        try:
            target_checkout.destroySelf()
        except:
            log.err( 'could not destroy checkout. party_id: %d, checkout_id: %d' % ( party_id, checkout_id ) )
            log.err()
            raise xmlrpc.Fault( 123, 'could not release submitted checkout' )

        return True
    
    xmlrpc_delCheckout.signature = [ ['bool','int','int'] ]
    
    def xmlrpc_addCheckout(self, party_id, env_id ):
        """checkout an environment for a particular party"""
        
        if not int( env_id ) and not int( party_id ):
            raise xmlrpc.Fault( 123, 'invalid arguments' )
        
        env = getEnvironmentById( env_id )
        party = getPartyById( party_id )
        
        # check for existing checkout of this environment
        if Checkout.select( Checkout.q.environment == env_id ).count() > 0:
            log.err( 'attempt to checkout an already checked-out environment. party_id: %d, env_id: %d' % ( party_id, env_id ) )
            raise xmlrpc.Fault( 123, 'submitted environment is already checked out' )

        try:
            checkout = Checkout( environment = env, party = party )
        except:
            log.err( 'could not create new checkout. party_id: %d, env_id: %d' % ( party_id, env_id ) )
            log.err()
            raise xmlrpc.Fault( 123, 'could not create checkout' )

        return checkout.id
    
    xmlrpc_addCheckout.signature = [ ['int','int','int'] ]
    
    def checkoutResultToDict(self, checkout ):
            result = dict()
            result['id'] = checkout.id
            result['environment'] = checkout.environment.id
            result['party'] = checkout.party.id
            result['checkout_time'] = xmlrpc.DateTime( checkout.checkout_time ).value
            result['expiration_time'] = xmlrpc.DateTime( checkout.expiration_time ).value
            
            return result